/**
  ******************************************************************************
  * @file    IAP_Main/Src/flash_if.c 
  * @author  MCD Application Team
  * @version 1.0.0
  * @date    8-April-2015
  * @brief   This file provides all the memory related operation functions.
  * @note    2023/8/19/张剑勇。本文件为 STM32L031G6U6 进行了修改。
  *          
  ******************************************************************************
  * @attention
  ******************************************************************************
  */

#include "flash_if.h"

static uint32_t get_sector(uint32_t address)
{
  uint32_t sector = 0;
  
  if((address < ADDR_FLASH_SECTOR_1) && (address >= ADDR_FLASH_SECTOR_0))
  {
    sector = FLASH_SECTOR_0;  
  }
  else if((address < ADDR_FLASH_SECTOR_2) && (address >= ADDR_FLASH_SECTOR_1))
  {
    sector = FLASH_SECTOR_1;  
  }
  else if((address < ADDR_FLASH_SECTOR_3) && (address >= ADDR_FLASH_SECTOR_2))
  {
    sector = FLASH_SECTOR_2;  
  }
  else if((address < ADDR_FLASH_SECTOR_4) && (address >= ADDR_FLASH_SECTOR_3))
  {
    sector = FLASH_SECTOR_3;  
  }
  else if((address < ADDR_FLASH_SECTOR_5) && (address >= ADDR_FLASH_SECTOR_4))
  {
    sector = FLASH_SECTOR_4;  
  }
  else if((address < ADDR_FLASH_SECTOR_6) && (address >= ADDR_FLASH_SECTOR_5))
  {
    sector = FLASH_SECTOR_5;  
  }
  else if((address < ADDR_FLASH_SECTOR_7) && (address >= ADDR_FLASH_SECTOR_6))
  {
    sector = FLASH_SECTOR_6;  
  }
  else if((address < ADDR_FLASH_SECTOR_8) && (address >= ADDR_FLASH_SECTOR_7))
  {
    sector = FLASH_SECTOR_7;  
  }
  else if((address < ADDR_FLASH_SECTOR_9) && (address >= ADDR_FLASH_SECTOR_8))
  {
    sector = FLASH_SECTOR_8;  
  }
  else if((address < ADDR_FLASH_SECTOR_10) && (address >= ADDR_FLASH_SECTOR_9))
  {
    sector = FLASH_SECTOR_9;  
  }
  else if((address < ADDR_FLASH_SECTOR_11) && (address >= ADDR_FLASH_SECTOR_10))
  {
    sector = FLASH_SECTOR_10;  
  }
  else //if((address < ADDR_FLASH_SECTOR_12) && (address >= ADDR_FLASH_SECTOR_11))
  {
    sector = FLASH_SECTOR_11;  
  }
//  else if((address < ADDR_FLASH_SECTOR_13) && (address >= ADDR_FLASH_SECTOR_12))
//  {
//    sector = FLASH_SECTOR_12;  
//  }
//  else if((address < ADDR_FLASH_SECTOR_14) && (address >= ADDR_FLASH_SECTOR_13))
//  {
//    sector = FLASH_SECTOR_13;  
//  }
//  else if((address < ADDR_FLASH_SECTOR_15) && (address >= ADDR_FLASH_SECTOR_14))
//  {
//    sector = FLASH_SECTOR_14;  
//  }
//  else /* (address < FLASH_END_ADDR) && (address >= ADDR_FLASH_SECTOR_14) */
//  {
//    sector = FLASH_SECTOR_15;
//  }

  return sector;
}

/**
  * @brief  Gets sector Size
  * @param  None
  * @retval The size of a given sector
  */
static uint32_t get_sector_size_byte(uint32_t sector)
{
  uint32_t sectorsize = 0x00;

  if((sector == FLASH_SECTOR_0) || (sector == FLASH_SECTOR_1) || (sector == FLASH_SECTOR_2) || (sector == FLASH_SECTOR_3))
  {
    sectorsize = 16 * 1024;
  }
  else if(sector == FLASH_SECTOR_4)
  {
    sectorsize = 64 * 1024;
  }
  else
  {
    sectorsize = 128 * 1024;
  }
  
  return sectorsize;
}

/**
  * @brief  Unlocks Flash for write access
  * @param  None
  * @retval None
  */
void FLASH_If_Init(void)
{
  /* Unlock the Program memory */
  HAL_FLASH_Unlock();

  /* Clear all FLASH flags */
#if defined(FLASH_SR_RDERR)
  __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |
                         FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR |
                         FLASH_FLAG_RDERR | FLASH_FLAG_BSY);
#else
  __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR |
                         FLASH_FLAG_PGAERR | FLASH_FLAG_PGPERR | FLASH_FLAG_PGSERR |
                         FLASH_FLAG_BSY);
#endif /* FLASH_SR_RDERR */
  
  /* Unlock the Program memory */
  HAL_FLASH_Lock();
}

/**
  * @brief  This function does an erase of all user flash area
  * @param  start: start of user flash area
  * @retval FLASHIF_OK : user flash area successfully erased
  *         FLASHIF_ERASEKO : error occurred
  * @note   [zjy 20230819]
  */
uint32_t FLASH_If_Erase(uint32_t start)
{
  FLASH_EraseInitTypeDef desc;
  uint32_t result = FLASHIF_OK;

  HAL_FLASH_Unlock();
  
  desc.VoltageRange = FLASH_VOLTAGE_RANGE_3;
  desc.Banks = FLASH_BANK_1;
  desc.Sector = start;
  desc.TypeErase = FLASH_TYPEERASE_SECTORS;  
  desc.NbSectors = get_sector(APPLICATION_END_ADDRESS) - get_sector(APPLICATION_ENTRY_ADDRESS) + 1;
  
  if(HAL_FLASHEx_Erase(&desc, &result) != HAL_OK)
  {
    result = FLASHIF_ERASEKO;
  }
  
  HAL_FLASH_Lock();

  return result;
}	

/* Public functions ---------------------------------------------------------*/
/**
  * @brief  This function writes a data buffer in flash (data are 32-bit aligned).
  * @note   After writing data buffer, the flash content is checked.
  * @param  destination: start address for target location
  * @param  p_source: pointer on buffer with data to write
  * @param  length: length of data buffer (unit is 32-bit word)
  * @retval uint32_t 0: Data successfully written to Flash memory
  *         1: Error occurred while writing data in Flash memory
  *         2: Written Data in flash memory is different from expected one
  * @note   2023/8/19/张剑勇。
  *         本部分移植自“STM3210C_EVAL”工程，原“STM32L073Z_EVAL”工程中的代码不可用。
  *         上位机下载bin文件时，不可使用“teraterm”工具，应使用“SecureCRT 8.7”，
  *         否则，无法成功下载和烧写用户程序。
  */
uint32_t FLASH_If_Write(uint32_t destination, uint32_t *p_source, uint32_t length)
{
  uint32_t i = 0;

  /* Unlock the Flash to enable the flash control register access *************/
  HAL_FLASH_Unlock();

  for (i = 0; (i < length) && (destination <= (USER_FLASH_END_ADDRESS-4)); i++)
  {
    /* Device voltage range supposed to be [2.7V to 3.6V], the operation will
       be done by word */ 
    if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, destination, *(uint32_t*)(p_source+i)) == HAL_OK)      
    {
     /* Check the written value */
      if (*(uint32_t*)destination != *(uint32_t*)(p_source+i))
      {
        /* Flash content doesn't match SRAM content */
        return(FLASHIF_WRITINGCTRL_ERROR);
      }
      /* Increment FLASH destination address */
      destination += 4;
    }
    else
    {
      /* Error occurred while writing data in Flash memory */
      return (FLASHIF_WRITING_ERROR);
    }
  }

  /* Lock the Flash to disable the flash control register access (recommended
     to protect the FLASH memory against possible unwanted operation) *********/
  HAL_FLASH_Lock();

  return (FLASHIF_OK);

  
  
  
  
//  uint32_t status = FLASHIF_OK;
//  uint32_t *p_actual = p_source; /* Temporary pointer to data that will be written in a half-page space */
//  uint32_t i = 0;

//  HAL_FLASH_Unlock();

//  while (p_actual < (uint32_t*)(p_source + length))
//  {    
//    /* Write the buffer to the memory */
//    if (HAL_FLASHEx_HalfPageProgram( destination, p_actual ) == HAL_OK) /* No error occurred while writing data in Flash memory */
//    {
//      /* Check if flash content matches memBuffer */
//      for (i = 0; i < WORDS_IN_HALF_PAGE; i++)
//      {
//        if ((*(uint32_t*)(destination + 4 * i)) != p_actual[i])
//        {
//          /* flash content doesn't match memBuffer */
//          status = FLASHIF_WRITINGCTRL_ERROR;
//          break;
//        }
//      }

//      /* Increment the memory pointers */
//      destination += FLASH_HALF_PAGE_SIZE;
//      p_actual += WORDS_IN_HALF_PAGE;
//    }
//    else
//    {
//      status = FLASHIF_WRITING_ERROR;
//    }

//    if ( status != FLASHIF_OK )
//    {
//      break;
//    }
//  }

//  HAL_FLASH_Lock();

//  return status;
}	

///**
//  * @brief  Returns the write protection status of application flash area.
//  * @param  None
//  * @retval If a sector in application area is write-protected returned value is a combinaison
//            of the possible values : FLASHIF_PROTECTION_WRPENABLED, FLASHIF_PROTECTION_PCROPENABLED, ...
//  *         If no sector is write-protected FLASHIF_PROTECTION_NONE is returned.
//  */
//uint32_t FLASH_If_GetWriteProtectionStatus(void)
//{
//  FLASH_OBProgramInitTypeDef config;
//  FLASH_AdvOBProgramInitTypeDef adv_config;
//  uint32_t wrp1_status = 0, wrp2_status = 0, sectornumber = 0;
//  uint32_t protected = FLASHIF_PROTECTION_NONE;

//  /* Get the current configuration */
//  HAL_FLASHEx_OBGetConfig( &config );
//  HAL_FLASHEx_AdvOBGetConfig( &adv_config );

//  sectornumber = FLASH_SECTOR_NUMBER;

//  /* Not taking application size into account, all the memory starting the beginning address is checked */
//  /* As the APPLICATION_ADDRESS is a define constant, this code may be omitted by the optimization in   */
//  /* compiler. However it is present for case of user specified APPLICATION_ADDRESS value.               */
////  if ( adv_config.BootConfig == OB_BOOT_BANK1 )  /* Test on the user application to be ran in Bank1 */
//  {
//    if (sectornumber < 32)
//    {
//      wrp1_status = config.WRPSector & FLASH_PROTECTED_SECTORS;
//      wrp2_status = config.WRPSector2 & OB_WRP2_AllPages;
//    }
//    else
//    {
//      wrp1_status = config.WRPSector;
//      wrp2_status = config.WRPSector2 & ~(uint32_t)((1 << (sectornumber - 32 ) - 1));
//    }
//  }
//  else /* running from bank 2 */
//  {
//    if (sectornumber < 32)
//    {
//      wrp1_status = config.WRPSector & ( FLASH_PROTECTED_SECTORS | (~FLASH_BANK1_MASK) );
//      wrp2_status = config.WRPSector2 & OB_WRP2_AllPages;
//    }
//    else
//    {
//      wrp1_status = config.WRPSector & (~FLASH_BANK1_MASK);
//      wrp2_status = config.WRPSector2 & ~(uint32_t)((1 << (sectornumber - 32 ) - 1));
//    }
//  }

//  /* Final evaluation of status */
//  if ((wrp1_status != 0) || (wrp2_status != 0))
//  {
//    protected = FLASHIF_PROTECTION_WRPENABLED;
//  }
//  
//  return protected;	
//}

///**
//  * @brief  Configure the write protection status of user flash area.
//  * @param  protectionstate : FLASHIF_WRP_DISABLE or FLASHIF_WRP_ENABLE the protection
//  * @retval uint32_t FLASHIF_OK if change is applied.
//  */
//uint32_t FLASH_If_WriteProtectionConfig(uint32_t protectionstate)
//{
//  FLASH_OBProgramInitTypeDef config_new, config_old;
//  FLASH_AdvOBProgramInitTypeDef adv_config;
//  HAL_StatusTypeDef result;
//  uint32_t sectornumber = 0;

//  sectornumber = FLASH_SECTOR_NUMBER;

//  /* Get the current configuration */
//  HAL_FLASHEx_OBGetConfig( &config_old );
//  HAL_FLASHEx_AdvOBGetConfig( &adv_config );

//  /* The parameter says whether we turn the protection on or off */
//  config_new.WRPState = (protectionstate == FLASHIF_WRP_ENABLE ? OB_WRPSTATE_ENABLE : OB_WRPSTATE_DISABLE);

//  /* We want to modify only the Write protection */
//  config_new.OptionType = OPTIONBYTE_WRP;
//  
//  /* No read protection, keep BOR and reset settings */
//  config_new.RDPLevel = OB_RDP_LEVEL0;
//  config_new.BORLevel = config_old.BORLevel;
//  config_new.USERConfig = config_old.USERConfig;

//  /* Not taking application size into account, all the memory starting the beginning address is checked */
//  /* As the APPLICATION_ADDRESS is a define constant, this code may be omitted by the optimization in   */
//  /* compiler. However it is present for case of user specified APPLICATION_ADDRESS value.               */
//  /* Not taking application size into account, all the memory starting the beginning address is modified */
//  if ( adv_config.BootConfig != OB_BOOT_BANK1 ) /* BANK2 active for boot */
//  {
//    if (sectornumber < 32)
//    {
//      config_new.WRPSector = FLASH_BANK1_MASK & (config_old.WRPSector | FLASH_PROTECTED_SECTORS);
//      config_new.WRPSector2 = config_old.WRPSector2 | OB_WRP2_AllPages;
//    }
//    else
//    {
//      config_new.WRPSector = FLASH_BANK1_MASK;
//      config_new.WRPSector2 = config_old.WRPSector2 | (~(uint32_t)((1 << (sectornumber - 32)) - 1));
//    }
//  }
//  else /* Memory ordering normal */
//  {
//    if (sectornumber < 32)
//    {
//      config_new.WRPSector = config_old.WRPSector | FLASH_PROTECTED_SECTORS;
//      config_new.WRPSector2 = config_old.WRPSector2 | OB_WRP2_AllPages;
//    }
//    else
//    {
//      config_new.WRPSector = 0;
//      config_new.WRPSector2 = config_old.WRPSector2 | (~(uint32_t)((1 << (sectornumber - 32)) - 1));
//    }
//  }

//  /* Initiating the modifications */
//  result = HAL_FLASH_OB_Unlock();

//  /* program if unlock is successful */
//  if (result == HAL_OK)
//  {
//    HAL_FLASHEx_AdvOBProgram(&adv_config);
//    result = HAL_FLASHEx_OBProgram(&config_new);
//  }

//  return (result == HAL_OK ? FLASHIF_OK: FLASHIF_PROTECTION_ERRROR);
//}
/**
  * @}
  */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
